
local _ENV,_START = hf_setenv('data_worker',true)

local skynet = require "skynet.manager"
local cjson = require "cjson"
local server_def = require "server_def"
local util = require "util"
local dbdata = require "dbdata"
local constant = require "constant"
local error_code = require "error_code"
local sharedata = require "skynet.sharedata"
local reason = require "reason"
local events = require "events"
local mail_def   = require "mail_def"


local server_config = dofile(skynet.getenv("server_config"))

local table_insert = table.insert
local table_remove = table.remove
local table_unpack = table.unpack
local string_format = string.format
local math_floor = math.floor
local math_random = math.random
local math_abs                         = math.abs
local pairs = pairs
local ipairs = ipairs
local assert = assert
local tonumber = tonumber
local select = select



--[[
该模块主要管理游戏的基础数据,
做的事情就是从mongodb读出数据，写到redis中并返回给其它服务,
持久化的工作可通过消息队列的方式让外部程序去写
--]]

local sync_uids = {}

local CMD = {}

local init_coins = server_config.init_coins
local init_gems = server_config.init_roomcards
local init_roomcards = server_config.init_gems



function init()
    global_configs = nil
    dirty_queue_db = nil
    dirty_queue_key = nil
    redis_pool = nil 
    mongo_conf = nil
    mongo_pool = nil

    diff_time = 0
    hf_set_sentinel_end(_ENV)
end

function CMD.open()
    local redis_conf = {
        host = assert(server_config.redis_conf.host),
        port = assert(server_config.redis_conf.port),
        db = assert(server_config.redis_conf.db),
        auth = server_config.redis_conf.auth,
    }
    
    dirty_queue_db = assert(server_config.redis_conf.dirty_queue_db)
    dirty_queue_key = assert(server_config.redis_conf.dirty_queue_key)
    redis_pool = require("redis_pool").new(redis_conf)

    mongo_conf = {
        host = assert(server_config.mongo_base_conf.host),
        port = assert(server_config.mongo_base_conf.port),
        username = server_config.mongo_base_conf.user,
        password = server_config.mongo_base_conf.password,
        db_name = assert(server_config.mongo_base_conf.dbname),
        coll_name = assert(server_config.mongo_base_conf.collname),
        authdb = assert(server_config.mongo_db_conf.dbname),
    }
    mongo_pool = require("mongo_pool").new(mongo_conf)

    skynet.retpack(true)
end

--------------------------------数据库和缓存相关[begin]--------------------------------------
local function select_from_mongodb(uid)
    local client = mongo_pool:get_conn_from_pool()
    local db_name = mongo_conf.db_name
    local coll_name = mongo_conf.coll_name
    local ok,ret = xpcall(function()
        return client[db_name][coll_name]:findOne({_id = uid})
    end,debug.traceback)
    mongo_pool:putback_to_pool(client)
    if not ok then
        errlog(uid,ret)
        return
    end

    return ret
end
--------------------------------数据库和缓存相关[end]--------------------------------------

-----------------------------------数据存取相关--------------------------------
--先把数据写入,再做一个写标记，切记不可调换。用脚本同时可保证数据写入的原子性 key缓存一天失效
local update_redis_script = [[
    redis.call('set',KEYS[1],ARGV[1])
    redis.call('expire',KEYS[1], 86400)
    redis.call('select',KEYS[2])
    redis.call('hincrby',KEYS[3],ARGV[2],ARGV[3])
]]

local fix_base_data_for_miss_field

local function create_default_base_data(uid)
    local new_data = {uid = uid}
    fix_base_data_for_miss_field(new_data)
    return new_data
end

local function save_data_to_cache(uid,conn,data)
    local key = string_format('base_%d',uid)
    local data_str = cjson.encode(data)
    conn:eval(update_redis_script,3,key,dirty_queue_db,
        dirty_queue_key,data_str,uid,1)
    --dbglog(uid,'save data to cache',data_str)
end

local function ensure_data_in_cache(uid,conn)
    local key = string_format('base_%d',uid)
    local data = conn:get(key)
    --dbglog(uid,"-----ensure_data_in_cache-----",data)
    if data then
        data = cjson.decode(data)
        if fix_base_data_for_miss_field(data) then
            save_data_to_cache(uid,conn,data)
        end
    else
        --缓存没命中，在数据库里？我们需要到mongodb上找去
        data = select_from_mongodb(uid)
        if not data then
            --数据库也没有，这是一个新玩家，我们用默认的数据吧
            data = create_default_base_data(uid)
            save_data_to_cache(uid,conn,data)
        else
            fix_base_data_for_miss_field(data)
            --写到缓存中去吧
            save_data_to_cache(uid,conn,data)
        end  
    end

    return dbdata.new_from('data',data)
end

---------------------------------------数据存取相关------------------------------------

--------------------------------并发控制相关[begin]-------------------------------
local function wrapper_f(f,uid,conn,...)
    local data = assert(ensure_data_in_cache(uid,conn),
        string_format('could not fetch data <%s>',tostring(uid)))
    local ret = {f(uid,data,...)}
    if data:is_dirty() then
        save_data_to_cache(uid,conn,data:deep_copy())
    end

    if #ret > 0 then
        skynet.retpack(table_unpack(ret))
    else
        skynet.retpack()
    end
end

local function sync_run_by_uid(uid,f,...)
    local waiting_list = sync_uids[uid]
    if waiting_list == nil then
        sync_uids[uid] = true
    else
        if waiting_list == true then
            waiting_list = {}
            sync_uids[uid] = waiting_list
        end
        local co = coroutine.running()
        table_insert(waiting_list,co)
        skynet.wait(co) --等待唤醒
    end

    local conn = redis_pool:get_conn_from_pool()
    local ok,ret = xpcall(wrapper_f,debug.traceback,f,uid,conn,...)
    redis_pool:putback_to_pool(conn)

    if not ok then errlog(ret) end

    --再接着调度
    local waiting_list = sync_uids[uid]
    if waiting_list == true or #waiting_list == 0 then
        sync_uids[uid] = nil
        return
    end

    local co = table_remove(waiting_list,1)
    skynet.wakeup(co)
end
--------------------------------并发控制相关[end]-------------------------------
fix_base_data_for_miss_field = function(data)
    local changed = false
    if not data.coins then
        data.coins = init_coins
        changed = true
    end
    if not data.gems then
        data.gems = init_gems
        changed = true
    end
    if not data.max_gems then
        data.max_gems = data.gems
        changed = true
    end
    if not data.roomcards then
        data.roomcards = init_roomcards
        changed = true
    end
    if not data.rate_of_winning then
        data.rate_of_winning = {}
        changed = true
    end
    -- if not data.win_times then
    --     data.win_times = 0
    --     changed = true
    -- end
    -- if not data.losing_times then
    --     data.losing_times = 0
    --     changed = true
    -- end
    if not data.created_time then
        data.created_time = util.get_now_time()
        changed = true
    end
    if not data.compensation_times then
        data.compensation_times = 0
        changed = true
    end
    if not data.last_cross_day_time then
        data.last_cross_day_time = 0
        changed = true
    end
    if not data.last_cross_timing_time then
        data.last_cross_timing_time = 0
        changed = true
    end
    if not data.jiabei_cards then
        data.jiabei_cards = 0
        changed = true
    end
    if not data.card_note_count then
        data.card_note_count = 1
        changed = true
    end
    if not data.card_note_end_time then
        data.card_note_end_time = 0
        changed = true
    end
    if not data.coins_locked then
        data.coins_locked = 0
        changed = true
    end
    if not data.club_play_times then
        data.club_play_times = 0
        changed = true
    end
    --增加保险箱功能
    if not data.safe_box then
        data.safe_box = 0
        changed = true
    end
    if not data.lose_coins then
        data.lose_coins = 0
        changed = true
    end
    if not data.last_lase_coins_time then
        data.last_lase_coins_time = 0
        changed = true
    end
    --增加个人概率设置
    if not data.affect_count then
        data.affect_count = 0
        changed = true
    end
    if not data.affect_rate then
        data.affect_rate = 0
        changed = true
    end
    if not data.affect_state then
        data.affect_state = 0
        changed = true
    end
    if not data.affect_id then
        data.affect_id = 0
        changed = true
    end
    -- if not data.init_control_coins then
    --     data.init_control_coins = 0
    --     changed = true
    -- end
    -- if not data.curr_control_coins then
    --     data.curr_control_coins = 0
    --     changed = true
    -- end
    -- if not data.curr_control_weight then
    --     data.curr_control_weight = 0
    --     changed = true
    -- end
    -- if not data.curr_control_status then
    --     data.curr_control_status = 0
    --     changed = true
    -- end
    -- if not data.control_win_rate then
    --     data.control_win_rate = 0
    --     changed = true
    -- end
    -- if not data.control_lose_rate then
    --     data.control_lose_rate = 0
    --     changed = true
    -- end
    -- if not data.is_control_hundred_game then
    --     data.is_control_hundred_game = 0
    --     changed = true
    -- end
    if not data.charge_count then
        data.charge_count = 0
        changed = true
    end

    if not data.week_award then
        data.week_award = {}
        data.week_award.day_count = 1
        data.week_award.last_check_time = 0
        data.week_award.last_award = 0
        data.week_award.total_award = 0
        data.week_award.today_coins_water = 0
        data.week_award.can_exchange_award = 0
        changed = true
    end

    if not data.pay_money then
        data.pay_money = 0
        changed = true
    end

    if not data.play_time then
        data.play_time = 0
        changed = true
    end

    local now = util.get_now_time()
    if not data.today_win_coins then
        data.today_win_coins = 0
        changed = true
    end
    if not data.last_tw_coins_time then
        data.last_tw_coins_time = now
        changed = true
    end
    if not data.today_exchange_coins then --今日兑换
        data.today_exchange_coins = 0
        changed = true
    end
    if not data.exchange_coins then --累计兑换
        data.exchange_coins = 0
        changed = true
    end   
    if not data.last_te_coins_time then
        data.last_te_coins_time = now
        changed = true
    end
    if not data.today_online_seconds then
        data.today_online_seconds = 0
        changed = true
    end
    if not data.last_to_seconds_time then
        data.last_to_seconds_time = now
        changed = true
    end
    
    --fishing
    if not data.winlose_coins then     --捕鱼玩家输赢
        data.winlose_coins = 0
        changed = true
    end

    if not data.jackpots then           --捕鱼玩家个人奖池
        data.jackpots = {}
        changed = true
    end

    if not data.contribution then       --玩家贡献
        data.contribution = {}
        changed = true
    end

    if not data.hitrate then            --玩家概率
        data.hitrate = 1
        changed = true
    end

    if not data.person_rate then         --个人概率控制
        data.person_rate = 1
        changed = true
    end

    if not data.person_water then            --个人流水
        data.person_water = 0
        changed = true
    end

    if not data.person_water2 then            --达到首充要求后的个人流水
        data.person_water2 = 0
        changed = true
    end

    if not data.person_water_today then     --当日流水
        data.person_water_today = 0
        changed = true
    end

    if not data.person_water_month then    --当月流水
        data.person_water_month = 0
        changed = true
    end

    if not data.person_water_today_copy then --一日流水副本
        data.person_water_today_copy = 0
        changed = true
    end

    if not data.person_water_copy_time then -- 流水副本时间
        data.person_water_copy_time = 0
        changed = true
    end

    if not data.vip_level then
        data.vip_level = 0
        changed = true
    end

    if not data.total_free_times then     --老虎机总共获得的免费次数
        data.total_free_times = 0
        changed = true
    end

    if not data.free_times_data then      --获的免费次数时的下注额度和押线
        data.free_times_data = {}
        changed = true
    end

    if not data.last_caishen_trigger_time then
        data.last_caishen_trigger_time = 0
        changed = true
    end

    if not data.bind_uid then
        data.bind_uid = 0
        changed = true
    end
    if not data.play_count then --玩牌局数
        data.play_count = 0
        changed = true
    end

    if not data.fish_guns then
        data.fish_guns = {}
        changed = true
    end

    if not data.first_charge_status then
        data.first_charge_status = 0
        changed = true
    end

    if not data.ex_money then
        data.ex_money = 0
        changed = true
    end

    if not data.total_win_coins then
        data.total_win_coins = 0
        changed = true
    end

    if not data.total_lose_coins then
        data.total_lose_coins = 0
        changed = true
    end

    if not data.total_fee_coins then
        data.total_fee_coins = 0
        changed = true
    end

     if not data.club_info then
        data.club_info = {}
        data.club_info.club_id = 0
        data.club_info.last_play_time = 0
        changed = true
    end

    if not data.award_info then
        data.award_info = {}
        data.award_info.award_free_times = 0
        data.award_info.free_valid_time = 0
        changed = true
    end

    --兑换所需
    if not data.exchange_need_water then
        data.exchange_need_water = 0
        changed = true
    end

    --我的抢红包战绩
    if not data.qhb_record then
        data.qhb_record = {}
        changed = true
    end

    --我的发红包战绩
    if not data.fhb_record then
        data.fhb_record = {}
        changed = true
    end

    --今日总充值
    if not data.today_pay_money then
        data.today_pay_money = 0
        changed = true
    end

    --今日金钱时间戳
    if not data.pay_money_time then
        data.pay_money_time = 0
        changed = true
    end

    --首次充值时间
    if not data.first_recharge_time then
        data.first_recharge_time = 0
        changed = true
    end
    --最后充值时间
    if not data.last_recharge_time then
        data.last_recharge_time = 0
        changed = true
    end

    --游戏胜负（扣台费）
    if not data.win_lose_today then
        data.win_lose_today = 0
        changed = true
    end

    --游戏胜负副本（扣台费）
    if not data.win_lose_today_copy then
        data.win_lose_today_copy = 0
        changed = true
    end

    -- if not data.speedup_values then
    --     data.speedup_values = {}
    --     changed = true
    -- end

    --每日首充
    if not data.day_charge_status then
        data.day_charge_status = 0
        changed = true
    end    

    --gm控制
    if not data.gm_control then
        data.gm_control = {}
        data.gm_control.weight    = 0 --权重值
        data.gm_control.win_rate  = 0
        data.gm_control.lose_rate = 0
        data.gm_control.control_coins = 0
        data.gm_control.control_coins_init = 0
        data.gm_control.is_control_hundred_game = 0 
        data.gm_control.oper_user = ""
        changed = true
    end

    --个控 
    if not data.personal_control then
        data.personal_control = {}
        data.personal_control.control_coins_init = 0
        data.personal_control.control_coins = 0
        data.personal_control.weight = 0
        data.personal_control.win_rate  = 0
        data.personal_control.lose_rate = 0
        changed = true
    end

    return changed
end



--救援金
local function rescue(uid,data,win_lose)
    dbglog("rescue",uid, win_lose, data.vip_level)
    if win_lose and win_lose >= 0 then return end
    events.on_rescue_win_lose({uid=uid, water=math_abs(win_lose), vip_level=data.vip_level})
end
--返水
local function back_water(uid,data,water,time)
    if water == 0 or time == 0 then return end
    events.on_return_water_arward({uid=uid,water = water,time = time})
    -- water = math_floor(water)
    -- local str_date = os.date("%Y/%m/%d",time)
    -- local water_award = global_configs.water_award
    -- if not water_award then return end
    -- for _,v in pairs(water_award) do
    --     if v.min_water <= water and (not v.max_water or water <= v.max_water) then
    --         local coins = math_floor(water * v.rate / 100)
    --         local succ,channel = R().dbsvr({key=uid}):call('.msg_handler','get_player_channel',uid)
    --         add_coins(uid,data,coins,reason.WATER_RETRUN,{channel = channel or ''})

    --         local mail_list = {}
    --         local mail = {}
    --         mail.uid = uid
    --         mail.title = string.format(mail_def.BACK_WATER_TITLE,str_date)
    --         mail.content = string.format(mail_def.BACK_WATER_CONTENT,str_date,water/100,coins/100)
    --         mail.coins = 0
    --         mail.mail_type = 2
    --         mail.op_user = mail_def.OP_USER
    --         table_insert(mail_list,mail)

    --         print("send_back_water=========",tostring_r(mail_list))
    --         local url = constant.ADD_MAIL_URL
    --         R().hallsvr(1):call('.msg_handler','common_post_data',url,{award_list = mail_list})
    --         return true
    --     end
    -- end
end

--检测充值跨天
local function check_pay_money_cross_day(uid,data)
    local curr_time = util.get_now_time() + (diff_time or 0)
    if util.is_same_day(data.pay_money_time,curr_time) then
        return
    end
    data.today_pay_money = 0
    data.pay_money_time = curr_time
end

--检测打码量 低于玩家金币
local function check_exchange_need_water(uid,data)
    local damaliang_conf = global_configs.damaliang or {}
    local min_coins = damaliang_conf.min_coins or 0
    local all_coins = data.safe_box + data.coins
    if all_coins < data.exchange_need_water and all_coins <= min_coins then
        data.exchange_need_water = all_coins
    end
end


--检测跨天
local function check_cross_day(uid,data,last_time,curr_time)
    if util.is_same_day(last_time,curr_time) then
        return false
    end

    --有未结算的流水返水
    if data.person_water_today_copy and data.person_water_today_copy ~= 0 then
        back_water(uid,data,data.person_water_today_copy,data.person_water_copy_time)
    end

    rescue(uid,data,data.win_lose_today)

    --跨天保存流水输赢和日期
    data.person_water_today_copy = data.person_water_today
    data.person_water_copy_time = last_time

    data.win_lose_today = 0
    data.person_water_today = 0
    data.today_exchange_coins = 0
    data.today_win_coins = 0
    data.today_online_seconds = 0
    data.last_cross_day_time = curr_time
    data.day_charge_status = 0 --每日首充
    return true
end


local function is_same_sunup_day(t1,t2,hours)
    dbglog(t1,t2)
    local diff = 8*3600 - hours*3600
    t1 = t1 + diff
    t2 = t2 + diff
    return math_floor(t1/86400) == math_floor(t2/86400)
end

local function check_cross_sunup_day(uid,data,last_time,curr_time)
    if last_time == 0 or data.person_water_copy_time == 0 then return end
    dbglog(last_time,curr_time,util.is_same_sunup_day(last_time,curr_time,15))
    if util.is_same_sunup_day(last_time,curr_time,15) then
        return false
    end

    if util.is_same_day(data.person_water_copy_time,curr_time -15*3600) then
        return
    end
    --结算返水
    dbglog("============check_cross_sunup_day=========",data.person_water_copy_time,curr_time -15*3600)
    back_water(uid,data,data.person_water_today_copy,data.person_water_copy_time)
    -- rescue(uid,data,data.win_lose_today_copy)
    -- data.win_lose_today_copy = 0
    data.person_water_today_copy = 0
    data.person_water_copy_time = 0
    data.last_cross_day_time = curr_time
    return true
end

local function check_time_cross(uid,data)
    dbglog(util.get_now_time())
    local curr_time = util.get_now_time() + (diff_time or 0)
    dbglog(curr_time)
    local last_time = data.last_cross_day_time
    check_cross_day(uid,data,last_time,curr_time)
    check_cross_sunup_day(uid,data,last_time,curr_time)
    check_pay_money_cross_day(uid,data)
    
end 

local function clear_gm_control(data)
    if not data.gm_control then
        return
    end

    data.gm_control.weight    = 0 --权重值
    data.gm_control.win_rate  = 0
    data.gm_control.lose_rate = 0
    data.gm_control.control_coins = 0
    data.gm_control.control_coins_init = 0
    data.gm_control.is_control_hundred_game = 0
    data.gm_control.oper_user = ""
end

local function clear_personal_control(data)
    data.personal_control.control_coins_init = 0
    data.personal_control.control_coins = 0
    data.personal_control.win_rate = 0
    data.personal_control.lose_rate = 0
    data.personal_control.weight = 0
end

local function gm_billlog(uid, data, pre_control_coins, add_type, action_type, op_user)
    local log_data = {
       op = "control_data",
       uid = uid,
       control_type = 2,
       is_delete = false,
       add_type = add_type or 0, --0gm手动添加 1在线检测
       control_coins = data.gm_control.control_coins_init or 0, 
       pre_control_coins = pre_control_coins,
       curr_control_coins = data.gm_control.control_coins,--当前个人库存值
       curr_coins = data.coins, --玩家当前金额
       win_rate  = data.gm_control.win_rate,
       lose_rate = data.gm_control.lose_rate,
       shuying =  data.exchange_coins + data.coins - data.pay_money,
       is_control_hundred_game = data.gm_control.is_control_hundred_game,
       control_weight  = data.gm_control.weight,
       action_type = action_type, --0创建，1修改，2删除，
       op_user   = data.gm_control.oper_user or op_user or 'server',       
    }
    billlog(log_data)
    print("___control_data__gm_billlog___", log_data)
end

local function personal_billlog(uid, data, pre_control_coins, add_type, action_type, op_user)   
    local log_data = {
       op = "control_data",
       uid = uid,
       control_type = 1, --1表示个人控，2gm
       is_delete = false, --是否删除
       add_type = add_type or data.personal_control.add_type or 0, --0gm手动添加 1在线检测
       control_coins = data.personal_control.control_coins_init or 0, --控制金额
       pre_control_coins = pre_control_coins, --个控变化前
       curr_control_coins = data.personal_control.control_coins,--当前个人库存值
       curr_coins = data.coins, --玩家当前金额
       win_rate  = data.personal_control.win_rate, --赢钱概率
       lose_rate = data.personal_control.lose_rate, --输钱概率
       shuying =  data.exchange_coins + data.coins - data.pay_money, --玩家当前输赢值
       is_control_hundred_game = data.personal_control.is_control_hundred_game or 0, --是否百人场
       control_weight  = data.personal_control.weight,  --控制权重      
       action_type = action_type, --0创建，1修改，2删除，
       op_user   = op_user or 'server',
    }
    billlog(log_data)
    print("___control_data__personal_billlog___", log_data)
end

local function delete_control_billlog(uid, data, control_type)   
    local log_data = {
       op = "control_data",
       uid = uid,
       control_type = control_type, --1表示个人控，2gm
       is_delete = true, --是否删除
       add_type = 1, --0gm手动添加 1在线检测
       control_coins = 0, --控制金额
       pre_control_coins = 0, --个控变化前
       curr_control_coins = 0,--当前个人库存值
       curr_coins = data.coins, --玩家当前金额
       win_rate  = 0, --赢钱概率
       lose_rate = 0, --输钱概率
       shuying =  data.exchange_coins + data.coins - data.pay_money, --玩家当前输赢值
       is_control_hundred_game = 0, --是否百人场
       control_weight  = 0,  --控制权重      
       action_type = 2, --0创建，1修改，2删除，
       op_user = 'server',
    }
    billlog(log_data)
    print("___control_data__delete_control_billlog___", log_data)
end


--充值达到一定数，删除个控
local function vip_deletedata(uid,data)
    if not data.personal_control or (data.personal_control.control_coins or 0) == 0 then
        print("___1__vip_deletedata___", uid, data.personal_control)
        return
    end
    local control_common = global_configs.personal_control or {}
    print("___2__vip_deletedata___", uid, data.pay_money, control_common.xiaoR_level)
    if data.pay_money >= (control_common.xiaoR_level or 1000000) then
        clear_personal_control(data) --清空个人库存
        delete_control_billlog(uid, data, 1)
    end
end


local function add_coins(uid,data,coins,reason2,...)
    dbglog("____add_coins______",uid, reason2, coins, ...)
    if reason2 == reason.PAYMENT_SAFE_BOX then --加钱到保险柜
        data.safe_box = data.safe_box + coins
    else
        data.coins = data.coins + coins
    end

    local exchange_config = global_configs.exchange or {}
    if reason2 == reason.BUY_FROM_SHOP_RMB or reason2 == reason.PAYMENT_SAFE_BOX or reason2 == reason.PAYMENT_COINS then
        local extra_info = ... or {}
        local ex_coins = extra_info.ex_coins or 0      
        data.charge_count = data.charge_count + 1
        --充值时间
        local time = util.get_now_time()
        if data.first_recharge_time == 0 then
            data.first_recharge_time = time 
        end
        data.last_recharge_time = time
        check_time_cross(uid,data) --检查下跨天
        --总充值
        data.pay_money = (data.pay_money + coins) - ex_coins --减出加成的钱
        --今日总充值
        check_pay_money_cross_day(uid,data)
        data.today_pay_money = (data.today_pay_money + coins) - ex_coins --减出加成的钱
        data.exchange_need_water = data.exchange_need_water + (coins - ex_coins)*(exchange_config.recharge_times or 1)   -- 增加兑换所需流水（打码量）
        data.exchange_need_water = data.exchange_need_water + ex_coins*(exchange_config.bank_mall_times or 1) -- 彩金所需流水（打码量）
        data.ex_money = data.ex_money + ex_coins
        --判定充值额度是否清空个人控制
        vip_deletedata(uid,data)
        -- local charge_data = {uid = uid,pay_money = data.pay_money,today_pay_money = data.today_pay_money,charge_count = data.charge_count,pay_coins = coins- ex_coins}
        --首充
        events.on_recharge(data, coins- ex_coins, coins)
    elseif reason2 == reason.WATER_RETRUN then
        data.exchange_need_water = data.exchange_need_water + coins*(exchange_config.water_return_times or 1)   -- 增加兑换所需流水（打码量） 返水
    elseif reason2 == reason.VIP_REWARD then
       data.exchange_need_water = data.exchange_need_water + coins*(exchange_config.vip_reward_times or 1)   -- 增加兑换所需流水（打码量）VIP奖励
    elseif reason2 == reason.COINS_STORM then
        data.exchange_need_water = data.exchange_need_water + coins*(exchange_config.coins_storm_times or 1)   -- 增加兑换所需流水（打码量）暴风雨
    elseif reason2 == reason.SIGN_REWARD then
        data.exchange_need_water = data.exchange_need_water + coins*(exchange_config.sign_reward_times or 1)   -- 增加兑换所需流水（打码量）签到
    elseif reason2 == reason.SALARY_MONTH then
        data.exchange_need_water = data.exchange_need_water + coins*(exchange_config.salary_month_times or 1)   -- 增加兑换所需流水（打码量）月俸禄
    elseif reason2 == reason.GIVE_CAIJING then
        local extra_info = ... or {}
        local caijing_times = extra_info.caijing_times or 1   ---订单打码量倍数
        data.exchange_need_water = data.exchange_need_water + coins*caijing_times   -- 彩金所需流水（打码量）月俸禄
    elseif reason2 == reason.RESCUE then
        data.exchange_need_water = data.exchange_need_water + coins*(exchange_config.rescue_times or 1)
    elseif reason2 == reason.FIRST_CHARGE_RETRUN then
        data.exchange_need_water = data.exchange_need_water + coins*(exchange_config.first_recharge_times or 1)    
    elseif reason2 == reason.TREE then
        data.exchange_need_water = data.exchange_need_water + coins*(exchange_config.tree_times or 1)   
    elseif reason2 == reason.DAY_CHARGE then
        --每日首充打码量
        data.exchange_need_water = data.exchange_need_water + coins*(exchange_config.day_charge_times or 1)        
    end

    -- if reason2 == reason.WIN_COIN or reason2 == reason.FISHING_CATCH or reason2 == reason.FISHING_BACK_COINS or reason2 == reason.BET_COIN_BACK then
    --     data.total_win_coins = (data.total_win_coins or 0) + coins
    -- end

    --累积输赢
    if reason2 == reason.WIN_COIN or reason2 == reason.BET_COIN_BACK or reason2 == reason.FISHING_BACK_COINS or reason2 == reason.QHB_BACK or reason2 == reason.FHB_BACK then
        data.win_lose_today = (data.win_lose_today or 0) + coins
    else
        xpcall(check_exchange_need_water,debug.traceback,uid,data)
    end

    billlog({op="addcoins",uid = uid,curr = data.coins,value = coins,r = reason2},...)
    return true,{
        curr = data.coins,
        chged = coins,
        safe_box = data.safe_box,
    }
end




-----------------------------------协议-----------------------------------------
local function get_base_data(uid,data)
    return data
end

local function get_coins(uid,data)
    return data.coins
end

-------------------补助金------------------------
local function can_take_compensation(uid,data)
    -- --检查下跨天
    -- check_cross_day(uid,data)

    -- local times_limit = (global_configs.value.BASE_COMPENSATION_TIMES_LIMIT or 3)
    -- if data.coins >= (global_configs.value.BASE_COMPENSATION_COND or 30000) then
    --     return false,times_limit - data.compensation_times
    -- end

    -- if data.compensation_times >= times_limit then
    --     return -1,times_limit - data.compensation_times
    -- end

    -- return 0,times_limit - data.compensation_times
end

local function set_coins(uid,data,coins,reason,...)
    data.coins = coins

    -- billlog({op="setcoins",uid = uid,curr = data.coins,value = coins,r = reason},...)

    return true,{
        curr  = data.coins,
        chged = coins,
    }
end



local function add_lose_coins(uid,data,coins)
    data.lose_coins = data.lose_coins + coins
end

local function sub_lose_coins(uid,data,coins)
    data.lose_coins = data.lose_coins - coins
end

local function get_lose_coins(uid,data)
    local curr_time = util.get_now_time()
    if util.is_same_sunup_day(data.last_lase_coins_time,curr_time) then
        return data.lose_coins
    end

    data.last_lase_coins_time = curr_time
    data.lose_coins = 0
    return data.lose_coins
end

-- local function is_new(uid,data)
--     if data.curr_control_coins == 0 and 
--        data.curr_control_weight == 0 and 
--        data.curr_control_status == 0 then
--        return true
--     end

--     return false
-- end


-- local function reduce_control_coins_weight(uid,data,reduce_coins,reduce_weight,reason)
--     if is_new(uid,data) then
--         return {add = true}
--     end
    
--     data.curr_control_status = 1
--     data.curr_control_coins  = data.curr_control_coins - reduce_coins
--     if data.init_control_coins == 0 then
--         data.init_control_coins = data.curr_control_coins
--     end
--     if data.curr_control_weight == 0 then
--         data.curr_control_weight = data.curr_control_weight + reduce_weight
--     end


--     billlog({
--         op="reducecontrol",uid = uid,r = reason,
--         curr_control_coins = data.curr_control_coins,reduce_coins = reduce_coins,
--         curr_control_weight = data.curr_control_weight,reduce_weight = reduce_weight,
--     })

--     return {
--         init_control_coins  = data.init_control_coins,
--         curr_control_coins  = data.curr_control_coins,
--         curr_control_weight = data.curr_control_weight,
--         curr_status = data.curr_control_status,
--     }
-- end

-- local function add_control_coins_weight(uid,data,add_coins,add_weight,reason)
--     if is_new(uid,data) then
--         return {add = true}
--     end

--     local pre_control_coins  = data.curr_control_coins
--     local pre_control_weight = data.curr_control_weight

--     data.curr_control_status = 1
--     if data.curr_control_weight == 0 then
--         data.curr_control_weight = add_weight
--     end
--     if data.init_control_coins == 0 then
--         data.init_control_coins = add_coins
--     end

--     billlog({
--         op="addcontrol",
--         uid = uid,
--         r = reason,
--         curr_control_coins = data.curr_control_coins,
--         add_coins = add_coins,
--         curr_control_weight = data.curr_control_weight,
--         add_weight = add_weight,
--     })

--     return {
--         init_control_coins  = data.init_control_coins,
--         pre_control_coins   = pre_control_coins,
--         pre_control_weight  = pre_control_weight,
--         curr_control_coins  = data.curr_control_coins + add_coins,
--         curr_control_weight = data.curr_control_weight,
--         curr_status = data.curr_control_status,
--     }
-- end

local function reduce_coins(uid,data,coins,reason2,...)
    local lost_coins = coins
    local diff = data.coins - lost_coins
    if diff < 0 then
        return false
    end

    data.coins = data.coins - lost_coins

    if reason2 == reason.EXCHANGE_COINS then
        data.last_te_coins_time = util.get_now_time()
        check_time_cross(uid,data)
        data.today_exchange_coins = data.today_exchange_coins + coins
        data.exchange_coins = data.exchange_coins + coins
        events.today_fech_coins({ uid = uid, coins = data.today_exchange_coins})
        -- R().exdbsvr(1):send(".event_mgr", "trigger", "today_fech_coins", { uid = uid, coins = data.today_exchange_coins})
    end

    local exchange_config = global_configs.exchange or {}
    local exinfo = ... or {}
    local gm_type = exinfo.gm_type or 0
    if reason2 == reason.REDUCE_CAIJING and gm_type == 2 then
        data.exchange_need_water = data.exchange_need_water - coins*(exchange_config.caijing_times or 1)   -- 彩金所需流水（打码量）月俸禄
        data.exchange_need_water = data.exchange_need_water > 0 and data.exchange_need_water or 0
    end    

    if reason2 == reason.GM then
        if gm_type == 2 then --需要扣充值流水类型
            data.pay_money = data.pay_money - lost_coins
            data.pay_money = data.pay_money < 0 and 0 or data.pay_money
            data.today_pay_money = data.today_pay_money - lost_coins
            data.today_pay_money = data.today_pay_money < 0 and 0 or data.today_pay_money            
            local charge_data = {uid = uid,pay_money = data.pay_money,today_pay_money = data.today_pay_money}
            events.on_charge_coins_reduce(charge_data)
            -- R().exdbsvr(1):send(".event_mgr", "trigger", "on_charge_coins_reduce",charge_data)
            data.exchange_need_water = data.exchange_need_water - coins*(exchange_config.recharge_times or 1)   -- 减少兑换所需流水（打码量）
            data.exchange_need_water = data.exchange_need_water > 0 and data.exchange_need_water or 0
        end
    end

    -- if reason2 == reason.BET_COIN or reason2 == reason.PAY_FEE or reason2 == reason.FISHING_FIRE or reason2 == reason.LOSE_COIN then
    --     data.total_win_coins = (data.total_win_coins or 0) - coins
    -- end

    if reason2 == reason.BET_COIN then
        data.total_lose_coins = (data.total_lose_coins or 0) + coins
    end
    if reason2 == reason.PAY_FEE then
        data.total_fee_coins = (data.total_fee_coins or 0) + coins
    end

    if reason2 == reason.LOSE_COIN or reason2 == reason.BET_COIN or reason2 == reason.FISHING_FIRE or reason2 == reason.PAY_FEE or reason2 == reason.OPEN_CAISHEN then
        data.win_lose_today = (data.win_lose_today or 0) - coins
    else
        xpcall(check_exchange_need_water,debug.traceback,uid,data)
    end

    if reason2 == reason.OPEN_CAISHEN then
        data.total_win_coins = (data.total_win_coins or 0) - coins
    end

    billlog({op="reducecoins",uid = uid,safe_box = data.safe_box,curr = data.coins,value = lost_coins, r = reason2},...)
    return true,{
        curr = data.coins,
        chged = lost_coins,
    }
end

local function exchange_success(uid,data,coins,...)
    data.last_te_coins_time = util.get_now_time()
    check_time_cross(uid,data)
    data.today_exchange_coins = data.today_exchange_coins + coins
    data.exchange_coins = data.exchange_coins + coins
    events.today_fech_coins({ uid = uid, coins = data.today_exchange_coins})

    billlog({op="addcoins",uid = uid,curr = data.coins,value = coins,r = reason.EXCHANGE_COINS},...)
end

local function add_player_fee_coins(uid,data,coins,reason)
    data.total_fee_coins = (data.total_fee_coins or 0) + coins
end

local function reduce_coins_to_empty(uid,data,coins,reason,...)
    local lost_coins = coins
    local diff = data.coins - lost_coins
    if diff < 0 then
        lost_coins = data.coins
    end

    local extra_info = ...
    if extra_info then
        extra_info.intent = coins
    else
        extra_info = {intent = coins}
    end

    return reduce_coins(uid,data,lost_coins,reason,extra_info,select(2,...))
end

local function pay_one_ticket(uid,data,coins,reason,clear)
    local ret,t = reduce_coins(uid,data,coins,reason,clear)
    if not ret then
        return false
    end

    t.has_card_note = false
    local now = util.get_now_time()
    if data.card_note_end_time >= now then
        t.has_card_note = true
        return true,t
    end

    if data.card_note_count > 0 then
        data.card_note_count = data.card_note_count - 1
        t.has_card_note = true
    end

    --买了门票后就锁住钱
    data.coins_locked = now + 7200

    return true,t
end

local function can_reduce_coins(uid,data,coins)
    local able = false
    if data.coins >= coins then
        able = true
    end

   return able
end

local function caishen_coins(uid,data,coins,award_coins,...)
    if data.coins < coins then
        return false
    end

    data.coins = data.coins + award_coins - coins
    data.win_lose_today = (data.win_lose_today or 0) + award_coins - coins
    data.total_win_coins = (data.total_win_coins or 0) + award_coins - coins
    billlog({op="addcoins",uid = uid,curr = data.coins,value = award_coins - coins,r = reason.OPEN_CAISHEN},...)
    xpcall(check_exchange_need_water,debug.traceback,uid,data)
   return true,data.coins
end

local function can_add_safe_box(uid,data,coins)
    if not can_reduce_coins(uid,data,coins) then
        return false
    end

    --是否在房间里面
    local ok,table_gid = R().exdbsvr(1):call('.tlock_mgr','get_player_table',uid)
    if not ok then
        return false
    end

    if table_gid > 0 then
        return false
    end
    return true,table_gid
end

local function can_reduce_safe_box(uid,data,coins)
    if data.safe_box < coins then
        return false
    end

    --是否在房间里面
    local ok,table_gid = R().exdbsvr(1):call('.tlock_mgr','get_player_table',uid)
    -- if not ok then
    --     return false
    -- end

    -- if table_gid > 0 then
    --     return false
    -- end

   return true,table_gid
end

local function add_gems(uid,data,gems,reason,...)
    data.gems = data.gems + gems
    data.max_gems = data.max_gems + gems

    billlog({op="addgems",uid = uid,curr = data.gems,value = gems,r = reason},...)

    return true,{
        curr = data.gems,
        chged = gems
    }
end

local function reduce_gems(uid,data,gems,reason,...)
    if data.gems < gems then
        return false
    end

    data.gems = data.gems - gems

    billlog({op="reducegems",uid = uid,curr = data.gems,value = gems,r = reason},...)

    return true,{
        curr = data.gems,
        chged = gems
    }
end

local function can_reduce_gems(uid,data,gems)
    local able = false
    if data.gems >= gems then
        able = true
    end

    return able
end

local function add_roomcards(uid,data,roomcards,reason,...)
    data.roomcards = data.roomcards + roomcards

    billlog({op="addroomcards",uid = uid,curr = data.roomcards,value = roomcards,r = reason},...)

    return true,{
        curr = data.roomcards,
        chged = roomcards
    }
end

local function reduce_roomcards(uid,data,roomcards,reason,...)
    if data.roomcards < roomcards then
        return false
    end

    data.roomcards = data.roomcards - roomcards

    billlog({op="reduceroomcards",uid = uid,curr = data.roomcards,value = roomcards,r = reason},...)

    return true,{
        curr = data.roomcards,
        chged = roomcards
    }
end

local function can_reduce_roomcards(uid,data,roomcards)
    local able = false
    if data.roomcards >= roomcards then
        able = true
    end

    return able
end

local function add_jiabeicards(uid,data,item_id,count,reason,...)
    data.jiabei_cards = data.jiabei_cards + count

    billlog({op="add_item",uid = uid,cur = data.jiabei_cards,
        item_id,item_num = count,r = reason},...)

    return true,{
        curr = data.jiabei_cards,
        chged = count
    }
end

local function reduce_jiabeicards(uid,data,item_id,count,reason,...)
    if data.jiabei_cards < count then
        return false
    end
    data.jiabei_cards = data.jiabei_cards - count

    billlog({op="reduce_item",uid = uid,curr = data.jiabei_cards,
        item_id = item_id,item_num = count,r = reason},...)
    
    return true,{
        curr = data.jiabei_cards,
        chged = count
    }
end

local function can_reduce_jiabeicards(uid,data,count)
    local able = false
    if data.jiabei_cards >= count then
        able = true
    end

    return able
end

local function add_card_note_count(uid,data,item_id,item_num,reason,...)
    data.card_note_count = data.card_note_count + item_num

    billlog({op="add_item",uid = uid,cur = data.card_note_count,
        item_id = item_id,item_num = item_num,r = reason},...)

    return true,{
        curr = data.card_note_count,
        chged = item_num
    }
end

local function add_card_note_time(uid,data,item_id,item_num,reason,...)
    local add_second = 0
    if item_id == constant.ITEM_CNOTE_TWO_ID then --1天记牌器
        add_second = item_num * 24 * 60 * 60
    elseif item_id == constant.ITEM_CNOTE_THREE_ID then --7天记牌器
        add_second = item_num * 7 * 24 * 60 * 60
    else
        errlog(uid,'unknown itemid',item_id)
        return false
    end

    local now = util.get_now_time()
    data.card_note_end_time = math.max(data.card_note_end_time,now)
    data.card_note_end_time = data.card_note_end_time + add_second

    local day = math.ceil(data.card_note_end_time / (24 * 60 * 60)) 
    billlog({op="add_item",uid = uid,cur = day,item_id = item_id,item_num = item_num,r = reason},...)

    return true,{
        curr = data.card_note_end_time,
        chged = add_second
    }
end

local function take_compensation(uid,data,...)
    local ret = can_take_compensation(uid,data)
    if not ret then
        return false
    end

    if ret < 0 then
        return false
    end
    
    data.compensation_times = data.compensation_times + 1
    -- data.coins = data.coins + global_configs.value.BASE_COMPENSATION_COINS
    add_coins(uid, data, global_configs.value.BASE_COMPENSATION_COINS, reason.GAMECOIN_BANKRUPT)

    return true,{
        curr_coins = data.coins,
        compensation_times = data.compensation_times,
        compensation_coins = global_configs.value.BASE_COMPENSATION_COINS
    }
end

local function can_reduce_item(uid,data,item_id,item_num,reason)
    if item_id == constant.ITEM_COIN_ID then
        return can_reduce_coins(uid,data,item_num,reason)
    elseif item_id == constant.ITEM_GEM_ID then
        return can_reduce_gems(uid,data,item_num,reason)
    elseif item_id == constant.ITEM_ROOMCARD_ID then
        return can_reduce_roomcards(uid,data,item_num,reason) 
    elseif item_id == constant.ITEM_JIABEICARD_ID then
        return can_reduce_jiabeicards(uid,data,item_num,reason)   
    end

    return false
end


local function add_item(uid,data,item_id,item_num,reason,...)
    if item_id == constant.ITEM_COIN_ID then
        return add_coins(uid,data,item_num,reason, ...)
    elseif item_id == constant.ITEM_GEM_ID then
        return add_gems(uid,data,item_num,reason, ...)
    elseif item_id == constant.ITEM_ROOMCARD_ID then
        return add_roomcards(uid,data,item_num,reason, ...)
    elseif item_id == constant.ITEM_CNOTE_ONE_ID then
        return add_card_note_count(uid,data,item_id,item_num,reason, ...)
    elseif item_id == constant.ITEM_CNOTE_TWO_ID or 
           item_id == constant.ITEM_CNOTE_THREE_ID  then
        return add_card_note_time(uid,data,item_id,item_num,reason, ...)
    elseif item_id == constant.ITEM_JIABEICARD_ID then
        return add_jiabeicards(uid,data,item_id,item_num,reason, ...)
    end

    return false
end

local function reduce_item(uid,data,item_id,item_num,reason,...)
    if item_id == constant.ITEM_COIN_ID then
        return reduce_coins(uid,data,item_num,reason,...)
    elseif item_id == constant.ITEM_GEM_ID then
        return reduce_gems(uid,data,item_num,reason,...)
    elseif item_id == constant.ITEM_ROOMCARD_ID then
        return reduce_roomcards(uid,data,item_num,reason,...)
    elseif item_id == constant.ITEM_JIABEICARD_ID then
        return reduce_jiabeicards(uid,data,item_id,item_num,reason,...)
    end
    
    return false
end

local function buy(uid,data,req,reason,...)
    -- local cost_item = req.cost_item

    -- if cost_item.item_id == constant.ITEM_COIN_ID then
    --     local curr_time = util.get_now_time()
    --     if curr_time < data.coins_locked then
    --         return false,error_code.CANNOT_BUY_DURING_PLAYING
    --     end
    -- end
    -- if not can_reduce_item(uid,data,cost_item.item_id,cost_item.item_num,reason)
    -- then
    --     return false,error_code.NOT_ENOUGH_GEMS
    -- end

    -- if not reduce_item(uid,data,cost_item.item_id,cost_item.item_num,reason,...) then
    --     return false,-2
    -- end

    -- local bought_item = req.bought_item
    -- --不一定是买这边的道具
    -- local bought_id
    -- local bought_num
    -- if bought_item then
    --     add_item(uid,data,bought_item.item_id,bought_item.item_num,reason,...)
    --     bought_id = bought_item.item_id
    --     bought_num = bought_item.item_num
    -- end

    -- billlog({
    --     op="basebuy",uid = uid,cost_id = cost_item.item_id,
    --     cost_num = cost_item.item_num,bought_id = bought_id,
    --     bought_num = bought_num, r = reason.PAY_BY_SHOP_DETAIL
    -- },...)

    return false
end




local function take_mail_attach(uid,data,record,...)
    print("take_mail_attach=============",uid, data, record)

    local reason = record.reason or reason.TAKE_MAIL_ATTACH 
    if record.attach_list then
        for _,item in pairs(record.attach_list) do
           add_item(uid,data,item.id,item.count,reason,...)
        end
    end

    if record.coins and record.coins > 0 then
        add_coins(uid,data,record.coins,reason,...)
    end

    return true,{coins = data.coins}
end

local function add_fail_times(data,game_type)
    local str_game_type = tostring(game_type)
    local record = data.rate_of_winning[str_game_type]
    if not record then
        record = data.rate_of_winning:new_table_field(str_game_type)
        record.fail_times = 0
        record.win_times = 0
    end
    record.fail_times = record.fail_times + 1
    print(tostring(data.rate_of_winning[str_game_type]))
end

local function add_win_times(data,game_type)
    local str_game_type = tostring(game_type)
    local record = data.rate_of_winning[str_game_type]
    if not record then
        record = data.rate_of_winning:new_table_field(str_game_type)
        record.fail_times = 0
        record.win_times = 0
    end
    record.win_times = record.win_times + 1
end

local function pay_lost_coins(uid,data,coins,game_type,reason,...)
    local ret,t = reduce_coins(uid,data,coins,reason,...)
    if ret then
        add_fail_times(data,game_type)
    end

    data.coins_locked = 0

    return ret,t
end

local function give_won_coins(uid,data,coins,game_type,reason,...)
    local ret,t = add_coins(uid,data,coins,reason,...)
    add_win_times(data,game_type)

    data.coins_locked = 0

    return ret,t
end

local function add_losing_times(uid,data,game_type)
    add_fail_times(data,game_type)

    return true
end

local function add_wining_times(uid,data,game_type)
    add_win_times(data,game_type)

    return true
end

local function add_item_list(uid,data,item_list,reason,...)
    local ret = true
    for _,v in pairs(item_list) do
        if not add_item(uid,data,v.id,v.count,reason,...) then
            ret = false
        end
    end

    return ret,data
end

local function add_club_play_times(uid,data)
    data.club_play_times = data.club_play_times + 1
    return true
end



local function desposit_safe_box(uid,data,coins,reason,...)
    dbglog(...)
    local ok,gid = can_add_safe_box(uid,data,coins)
    if ok then
        data.safe_box = data.safe_box + coins
        reduce_coins(uid,data,coins,reason,...)
        billlog({op="desposit_safe_box",uid = uid,curr = data.coins,curr_safe_box = data.safe_box,value = coins})

        return true,{
            curr = data.coins,
            curr_safe_box = data.safe_box,
            table_gid = gid,
        }
    end
    return false
end

local function take_out_safe_box(uid,data,coins,reason,...)
    dbglog(...)    
    local ok,gid = can_reduce_safe_box(uid,data,coins)
    if ok then
        data.safe_box = data.safe_box - coins
        add_coins(uid,data,coins,reason,...)
        billlog({op="take_out_safe_box",uid = uid,curr = data.coins,curr_safe_box = data.safe_box,value = coins})

        return true,{
            curr = data.coins,
            curr_safe_box = data.safe_box,
            table_gid = gid,
        }
    end
    return false
end

local function get_safe_box(uid,data)
    return data.safe_box
end

-- local function is_affected(uid,data)
--     local affect_count = data.affect_count
--     local affect_rate = data.affect_rate
--     if affect_count == 0 and affect_rate == 0 then
--         return false
--     end

--     return true
-- end

local function reduce_affected_count(uid,data,value,game_type)
    local affect_count = data.affect_count
    local diff = affect_count - value
    if affect_count > 0 and diff < 0 then
        data.affect_count = diff
        data.affect_rate = -1 * data.affect_rate
    elseif affect_count < 0 and diff > 0 then
        data.affect_count = 0
        data.affect_rate = 0
        data.affect_state = 0
    else
        data.affect_count = diff
        if diff == 0 then
            data.affect_rate = 0
            data.affect_state = 0
        end
    end

    billlog({op="reduceaffectcount",uid = uid,curr = data.affect_count,
    rate = data.affect_rate,state = data.affect_state,value = value, game_type = game_type})
    
    return true,{
        affect_count = data.affect_count,
        affect_rate = data.affect_rate,
        chged = value,
    } 
end

local function set_affected_value(uid,data,affect_count,affect_rate,affect_id)
    --影响额度和概率必须同为正或者同为负
    if affect_count * affect_rate < 0 then
        return false
    end

    data.affect_count = affect_count
    data.affect_rate = affect_rate

    data.affect_state = 1           --影响状态1：进行中 0：未开始或已终止
    data.affect_id = affect_id

    if affect_count == 0 or affect_rate == 0 then
        data.affect_state = 0
    end

    billlog({op="setaffectcount",uid = uid,affect_count = affect_count,affect_rate = affect_rate,affect_id = affect_id})
    return true
end

-- local function get_curr_control_data(uid,data)
--     local data = {
--         uid = uid,
--         init_control_coins = data.init_control_coins,
--         curr_control_coins = data.curr_control_coins,
--         curr_control_status = data.curr_control_status,
--         curr_control_weight = data.curr_control_weight,
--         is_hundred_game = data.is_control_hundred_game,
--     }

--     return data
-- end

local function get_charge_count(uid,data)
    return data.charge_count
end

-- local function web_adddata(uid,data,info)
--     print("control_win_rate===========",uid,tostring_r(info))
--     local pre_control_coins  = data.curr_control_coins
--     local pre_control_weight = data.curr_control_weight

--     if info.init_control_coins then
--         data.init_control_coins = info.init_control_coins
--         data.curr_control_coins = info.init_control_coins
--     end
--     if info.curr_control_weight then
--         data.curr_control_weight = info.curr_control_weight
--     end
--     if info.win_rate then
--         data.control_win_rate = info.win_rate
--     end
--     if info.lose_rate then
--         data.control_lose_rate = info.lose_rate
--     end
--      if info.is_hundred_game then
--         data.is_control_hundred_game = info.is_hundred_game
--     end   
--     data.curr_control_status = 1

--     billlog({op="controladd",uid = uid,data = info})

--     return {
--         uid = uid,
--         init_control_coins  = data.init_control_coins,
--         pre_control_coins   = pre_control_coins,
--         curr_control_coins  = data.curr_control_coins,
--         pre_control_weight  = pre_control_weight,
--         curr_control_weight = data.curr_control_weight,
--         control_coins_change = data.curr_control_coins - pre_control_coins,
--         control_weight_change = data.curr_control_weight - pre_control_coins,
--         curr_status = data.curr_control_status
--     }
-- end

-- local function web_switch(uid,data,status)
--     data.curr_control_status = tonumber(status)

--     billlog({op="controlswitch",uid = uid,status = status})

--     return data.curr_control_status
-- end

-- local function delete_control_data(uid)
--     local url = "/api/v1/admin/stock/del"
--     R().hallsvr({key=uid}):send('.msg_handler', 'common_post',uid,url,{})
-- end

-- local function reduce_curr_control_data(uid,data,coins,game_type)
--     if data.curr_control_coins <= 0 then
--         --小于0的时候不会执行减操作
--         errlog("error to reduce control data",uid,data.curr_control_coins,coins,game_type)
--         return
--     end

--     data.curr_control_coins = data.curr_control_coins - coins
--     if data.curr_control_coins == 0 then
--         data.curr_control_coins = 0
--         data.curr_control_status = 0
--         local old_weight = data.curr_control_weight
--         data.curr_control_weight = 0
--         if old_weight < 200 then --权重少于200才清掉
--             delete_control_data(uid)
--         end
--     end

--     billlog({op="reducecontroldata",uid = uid,curr = data.curr_control_coins,value = coins})

--     return true
-- end

-- local function add_curr_control_data(uid,data,coins,game_type)
--     if data.curr_control_coins >= 0 then
--         --大于0的时候不会执行加操作
--         errlog("error to add control data",uid,data.curr_control_coins,coins,game_type)
--         return
--     end

--     data.curr_control_coins = data.curr_control_coins + coins
--     if data.curr_control_coins >= 0 then
--         data.curr_control_coins = 0
--         data.curr_control_status = 0
--         data.curr_control_weight = 0
--         data.control_win_rate  = 0
--         data.control_lose_rate = 0
--         delete_control_data(uid)
--     end
--     billlog({op="addcontroldata",uid = uid,curr = data.curr_control_coins,value = coins})

--     return true
-- end

---fishing---
local function sync_winlose(uid,data,coins,reason,...)

    data.winlose_coins = coins
    billlog({op="sync_winlose",uid = uid,curr = coins,r = reason},...)
end


local function get_winlose(uid,data)
    return data.winlose_coins
end

local function add_jackpots(uid,data,table_type,chg_jp,reason,...)

    local old_jp = data.jackpots[tostring(table_type)]
    if not old_jp then
        old_jp = 0
    end

    local curr_jp =  old_jp + chg_jp
    data.jackpots[tostring(table_type)] = curr_jp

    billlog({op="add_jackpots",uid = uid,curr = curr_jp,value = chg_jp,r = reason},...)
    return true,{curr = curr_jp,chged = chg_jp}
end

local function reduce_jackpots(uid,data,table_type,chg_jp,reason,...)

    local old_jp = data.jackpots[tostring(table_type)]
    if not old_jp or old_jp < chg_jp then
        return false
    end
    
    local curr_jp =  old_jp - chg_jp
    data.jackpots[tostring(table_type)] = curr_jp

    billlog({op="reduce_jackpots",uid = uid,curr = curr_jp,value = chg_jp,r = reason},...)
    return true,{curr = curr_jp,chged = add_jp}
end

local function get_jackpots(uid,data,table_type)

    local old_jp = data.jackpots[tostring(table_type)]
    if not old_jp then
        old_jp = 0
    end
    
    return old_jp
end



local function set_hitrate(uid,data,hitrate,reason,...)

    local oldrate = data.hitrate
    data.hitrate = hitrate

    billlog({op="set_hitrate",uid = uid,curr = hitrate,value = oldrate,r = reason},...)
    return true,hitrate
end

local function get_hitrate(uid,data)
    
    return data.hitrate
end

local function set_person_rate(uid,data,person_rate,reason,...)

    local oldrate = data.person_rate
    data.person_rate = person_rate

    billlog({op="set_person_rate",uid = uid,curr = person_rate,value = oldrate,r = reason},...)
    return true,person_rate
end

local function set_vip_level(uid,data,level)
    data.vip_level = level
    billlog({op="set_vip_level",uid = uid,pay_money = data.pay_money,vip_level = data.vip_level})

    return data.vip_level
end

local function get_vip_level(uid,data)
    check_pay_money_cross_day(uid,data)
     return data.vip_level
end

local function get_person_rate(uid,data)
    
    return data.person_rate
end


local function get_back_rate(seven_reward,coins)
    for k,v in pairs(seven_reward) do
        if coins >= v.coins_low and coins <= v.coins_hight then
            return v.back_rate / 100
        end
    end
    return 0
end
--------------------------------------暂时屏蔽注释周福利------------------
local function settle_coins_water(uid,data)
    local week_award = data.week_award
    local seven_reward = global_configs.seven_reward
    if not seven_reward then
        errlog("config not exist",uid)
        return
    end
    local yestoday_coins = week_award.today_coins_water
    local back_rate = get_back_rate(seven_reward,week_award.today_coins_water)
    local award = week_award.today_coins_water * back_rate
    if award > 0 then
        week_award.day_count = week_award.day_count + 1
    end

    week_award.today_coins_water = 0
    week_award.last_award = award
    week_award.total_award = week_award.total_award + award
    week_award.can_exchange_award = week_award.can_exchange_award + award
    week_award.last_check_time = util.get_now_time()
    billlog({op="settl_coins_water",uid = uid,day_count = week_award.day_count,award = award,total_award = week_award.total_award,yestoday_coins = yestoday_coins})
    
    return true
end

local function add_player_coins_water(uid,data,coins)
    -- local curr_time = util.get_now_time()
    -- local week_award = data.week_award
    -- last_check_time = week_award.last_check_time
    -- if not util.is_same_day(last_check_time,curr_time) then
    --     settle_coins_water(uid,data)
    -- end

    -- print("11111111111",coins)
    -- local today_coins_water = week_award.today_coins_water
    -- local curr_coins_water = today_coins_water + coins
    -- week_award.today_coins_water = curr_coins_water

    -- billlog({op="addcoinswater",uid = uid,curr = curr_coins_water,coins = coins,day_count = week_award.day_count})
    -- R().exdbsvr(1):send(".event_mgr", "trigger", "add_today_coins_water",uid,coins)
    -- events.add_today_coins_water(uid,coins)
    return true
    -- return {pre_coins_water = today_coins_water,curr_coins_water = curr_coins_water}
end

local function get_week_award_info(uid,data)
    local week_award = data.week_award
    last_check_time = week_award.last_check_time
    local curr_time = util.get_now_time()
    if not util.is_same_day(last_check_time,curr_time) then
        settle_coins_water(uid,data)
    end

    return {
        today_coins_water = week_award.today_coins_water,
        last_award = week_award.last_award,
        total_award = week_award.total_award,
        can_exchange_award = week_award.can_exchange_award,
        day_count = week_award.day_count,
    }
end

local function exchanged_coins(uid,data,coins,channel)
    local week_award = data.week_award

    if coins > week_award.can_exchange_award then
        errlog("can not exchange",uid,week_award.can_exchange_award,coins)
        return 
    end

    add_coins(uid,data,coins,reason.SEVEN_AWARD_EXCHANGE)

    week_award.can_exchange_award = week_award.can_exchange_award - coins
    week_award.day_count = 1
    
    billlog({op="exchange_coins",uid = uid,coins = coins,channel = channel})

    return {day_count = week_award.day_count,can_exchange_award = week_award.can_exchange_award,coins = data.coins}
end

local function get_exchange_record(uid,data)
    return data.week_award.exchange_record
end

local function set_week_award_day_count(uid,data,count)
    local week_award = data.week_award
    week_award.last_check_time = week_award.last_check_time - count * 24*60*60

    dbglog(uid,"set_week_award_day_count",count)
    return true
end

local function set_week_award_can_exchange_award(uid,data,award)
    local week_award = data.week_award
    week_award.can_exchange_award = award

    dbglog(uid,"set_week_award_can_exchange_award",award)

    return true
end

local function add_today_win_coins(uid,data,coins)
    data.last_tw_coins_time = util.get_now_time()
    data.today_win_coins = data.today_win_coins + coins
    events.today_win_coins({ uid = uid, coins = data.today_win_coins})
    -- R().exdbsvr(1):send(".event_mgr", "trigger", "today_win_coins", { uid = uid, coins = data.today_win_coins})
    return true
end

local function add_play_times(uid,data,times)
    data.play_time = data.play_time + times
    data.today_online_seconds = data.today_online_seconds + times
    data.last_to_seconds_time = util.get_now_time()
    events.today_online_seconds({ uid = uid, times = data.today_online_seconds})
    -- R().exdbsvr(1):send(".event_mgr", "trigger", "today_online_seconds", { uid = uid, times = data.today_online_seconds})
    return true
end

--从hallserver通知跨天了
local function player_cross_day(uid,data)
    check_time_cross(uid,data)
    data.day_charge_status = 0 --每日首充

    return true
end

local function player_cross_time(uid,data)
    check_time_cross(uid,data)
    return true 
end

local function get_today_data(uid,data)
    return {
        today_online_seconds = data.today_online_seconds,
        today_win_coins = data.today_win_coins,
        today_exchange_coins = data.today_exchange_coins,
    }
end

local function get_pay_money(uid,data)
    return data.pay_money
end

local function reduce_free_times(uid,data,times,reason,...)
    local free_times_data = data.free_times_data
    if #free_times_data < 1 then
        return false
    end
    local free_tiems_info = free_times_data[1]
    if free_tiems_info.times - times < 0 then
        return false
    end

    if data.total_free_times - times < 0 then
        return false
    end

    data.total_free_times = data.total_free_times - times
    free_tiems_info.times = free_tiems_info.times - times

    free_times_data = data.free_times_data
    local times_data = free_times_data[1]
    local ret_free_data = {last_bet_score = times_data.last_bet_score,last_bet_line = times_data.last_bet_line}

    if free_tiems_info.times == 0 then
        data.free_times_data:remove_from_array(1)
    end

    return true,{ret_free_data=ret_free_data,total_free_times=data.total_free_times}
end

local function add_free_times(uid,data,times_info,reason2,...)
    print("=======add_free_times=====",tostring_r(data.free_times_data))    
    local free_times
    --免费下注失败需要返还免费次数时，要将此次失败时扣除的免费次数还原到原位置，保证客户端与服务器数据一致
    if reason2 == reason.BET_FREE_TIMES_BACK and #data.free_times_data >= 1 then
        print("=========reason.BET_FREE_TIMES_BACK==",uid)
        free_times = data.free_times_data:insert_to_array(1)
    else     
        --data.free_times_data 是连续的tab，没有一个key为nil
        free_times = data.free_times_data:new_table_field(#data.free_times_data+1)
    end

    free_times.times = times_info.times --免费次数
    free_times.last_bet_score = times_info.last_bet_score --此次压注金额(单线)
    free_times.last_bet_line = times_info.last_bet_line   --此次压线数
    
    data.total_free_times = data.total_free_times + times_info.times
    print("=======add_free_times=====",tostring_r(data.free_times_data))   

    local free_times_data = data.free_times_data
    return true,{free_times_data=free_times_data[1],total_free_times=data.total_free_times}
end

local function check_caishen_trigger_time(uid,data,curr_time,interval)
    local last_caishen_trigger_time = data.last_caishen_trigger_time
    if curr_time - last_caishen_trigger_time > interval then
        data.last_caishen_trigger_time = curr_time
        print("111111111111111")
        return true
    end

    print("22222222222222222")
    return false
end

--个人流水
local function add_person_water(uid,data,water_value,is_robot)
    --时间检测
    check_time_cross(uid,data)

    data.exchange_need_water = data.exchange_need_water - water_value
    xpcall(check_exchange_need_water,debug.traceback,uid,data)
    if data.exchange_need_water < 0 then data.exchange_need_water = 0 end
    
    local curr_person_water = data.person_water + (water_value or 0)
    dbglog("curr_person_water:",curr_person_water,"water_value:",water_value)
    data.person_water = curr_person_water
    data.person_water_today = data.person_water_today + (water_value or 0)

    if not is_robot then 
        --通知别的服务器
        events.add_person_water(uid, data, water_value)
    end

    local vip = global_configs.vip
    if not vip then
         return true 
     end
    local lv = data.vip_level
    for _,info in pairs(vip) do 
        if info.level > data.vip_level and curr_person_water >= info.charge_coins then
            --data.vip_level = info.level
            set_vip_level(uid,data,info.level)
        end
    end
    if lv ~= data.vip_level and not is_robot then
        R().hallsvr{key=uid}:send('.msg_handler','on_vip_update',uid,data.vip_level)
    end
   
    return true
end

local function get_bind_uid(uid,data)
    return data.bind_uid
end

local function set_bind_uid(uid,data,bind_uid)
    print("set_bind_uid==============",uid,bind_uid)
    data.bind_uid = bind_uid
    billlog({op="player_bind",uid = uid,bind_uid = bind_uid})

    return true
end

local function add_play_count(uid,data,count)
    data.play_count = data.play_count + count
    events.on_add_play_count(uid,count)
    -- R().exdbsvr(1):send(".event_mgr", "trigger", "on_add_play_count",uid,count)

    return true
end

local function set_fish_gun(uid,data,gun_id,vip_up)
    if not vip_up and data.fish_guns.vip_new then
        return false
    end

    data.fish_guns.gun_id = gun_id
    data.fish_guns.vip_new = vip_up and true or false

    return true
end

local function get_fish_gun(uid,data,gun_id,vip_up)
    if data.fish_guns.vip_new then
        data.fish_guns.vip_new = false
    end
    -- 重新检查炮台是否开启（避免配置变更有未开启的炮台存在）
    local key = false
    local init_guns = 0
    for _,guns_info in pairs(global_configs.fishing_guns) do
        if guns_info.vip_level == 0 then init_guns = guns_info.id end
        if guns_info.vip_level <= data.vip_level and guns_info.id == data.fish_guns.gun_id then
            key = true
        end
    end
    if key then
        return data.fish_guns.gun_id or false
    end
     data.fish_guns.gun_id = init_guns
     return init_guns
end

local function check_player_first_charge(uid,data)
    if data.first_charge_status ~= 0 then
        return false
    end

    return true
end

--首充
local function update_first_charge_status(uid, data, status)
    data.first_charge_status = status
    return true
end

--每日首充
local function update_day_charge_status(uid, data, status)
    data.day_charge_status = status
    return true
end

local function get_club_id(uid,data)
    return data.club_info.club_id
end

local function set_club_id(uid,data,club_id)
    data.club_info.club_id = club_id
end

local function get_clubid_and_viplevel(uid,data)
    return data.club_info.club_id,data.vip_level
end

local function set_award_free_count(uid,data,info)
    if not data.award_info then
       data.award_info = {}
    end

    data.award_info.award_free_times = info.free_count or 0
    data.award_info.free_valid_time = info.time or 0

    return true
end

-- local function get_player_control_rate(uid,data)
--     return {win_rate = data.control_win_rate,lose_rate = data.control_lose_rate}
-- end

local function get_exchange_need_water(uid,data)
    return data.exchange_need_water
end

local function reduce_exchange_need_water(uid,data,coins)
    local value = data.exchange_need_water - coins
    if value < 0 then value = 0 end
    data.exchange_need_water = value
    return {exchange_need_water = value}
end

local function add_exchange_need_water(uid,data,coins)
    local value = data.exchange_need_water + coins
    if value < 0 then value = 0 end
    data.exchange_need_water = value    
    return {exchange_need_water = value}
end

local function check_exchange(uid,data,coins)
    if data.exchange_need_water >= 1 then 
        return 2
    end

    if data.coins < coins then
        return 1
    end
    return 0
end

local function add_qhb_record(uid,data,coins,num,coin,win_lose,is_lei)
    dbglog(uid,coins,num,coin,win_lose)
    local record_item = data.qhb_record:new_table_field(#data.qhb_record+1)
    record_item.coins = coins
    record_item.num = num
    record_item.win_lose = win_lose
    record_item.is_lei = is_lei

    if #data.qhb_record > 10 then
        data.qhb_record:remove_from_array(1)
    end
    dbglog(tostring_r(data.qhb_record))
end

local function get_qhb_record(uid,data)
    return data.qhb_record
end

local function add_fhb_record(uid,data,coins,hit_player_count,win_lose)
    dbglog("add_fhb_record",uid,coins,hit_player_count,win_lose)
    dbglog("add_fhb_record",type(data.fhb_record))
    dbglog("add_fhb_record",tostring_r(data.fhb_record))
    local record_item = data.fhb_record:new_table_field(#data.fhb_record+1)
    record_item.coins = coins
    record_item.hit_count = hit_player_count
    record_item.win_lose = win_lose

    if #data.fhb_record > 10 then
        data.fhb_record:remove_from_array(1)
    end
    dbglog("add_fhb_record",tostring_r(data.fhb_record))
end

local function get_fhb_record(uid,data)
    return data.fhb_record
end

--今日充值
local function get_welfare_info(uid,data)
    check_pay_money_cross_day(uid,data)
    return {
        today_pay_money = data.today_pay_money, 
        vip_level = data.vip_level,
        person_water = data.person_water,
        person_water_today = data.person_water_today,
    }
end

-- 重置时间(gm测试用的)
local function reset_time(uid,data,time)
    dbglog("reset_time")
    diff_time = time - util.get_now_time()
    check_time_cross(uid,data)
    local curr_time = util.get_now_time()
    if util.is_same_day(time, curr_time) then --不是一天
        data.day_charge_status = 0 --每日首充标记
    end    
end

-- 累计赢金
local function add_total_coins(uid,data,coins)
    dbglog("add_total_coins",coins)
    data.total_win_coins = (data.total_win_coins or 0) + coins
end

-- 累计投注
local function add_total_lose_coins(uid,data,coins)
    dbglog("add_total_lose_coins", coins)
    data.total_lose_coins = (data.total_lose_coins or 0) + coins
end


--今日输赢金（救援金用到
local function add_win_lose_coins(uid,data,coins)
    dbglog("__add_win_lose_coins",uid,coins)
    data.win_lose_today = (data.win_lose_today or 0) + coins
end

--检查gm 与 个控
local function check_clear_control_data(uid,data,gm_control)
    local control_common = global_configs.personal_control or {}
    if gm_control then
        print("check_clear_control_data111",data.gm_control.control_coins)
        if  data.gm_control.control_coins  == 0  then 
            clear_gm_control(data) --清空GM库存
            delete_control_billlog(uid, data, 2)            
        end
    else
        -- local value_min = data.personal_control.control_coins_init * (control_common.end_rate_min or 0) / 100
        print("check_clear_control_data222",data.personal_control.control_coins)
        if data.personal_control.control_coins == 0 then 
            clear_personal_control(data) --清空个人库存
            delete_control_billlog(uid, data, 1)     
        end
    end
end

local function delete_personal_control(uid,data)
    clear_personal_control(data)

    return true
end


--减少个控值
local function reduce_curr_control_data(uid,data,coins,table_type,gm_control)
    --GM控制
    print("reduce_curr_control_data===",gm_control,coins,data.gm_control.control_coins)
    local reduce_coins = 0
    if gm_control and data.gm_control.control_coins ~= 0 then
        reduce_coins = data.gm_control.control_coins <= coins and data.gm_control.control_coins or coins
        local pre_control_coins = data.gm_control.control_coins
        data.gm_control.control_coins = data.gm_control.control_coins - reduce_coins
        R().exdbsvr(1):send('.gm_coins_mgr','reduce_gm_coins',reduce_coins,{uid=uid,table_type = table_type,gm_control = true}) --减控制库存

        -- local log_data = {
        --     op="update_controldata",
        --     uid = uid,
        --     value = -reduce_coins,
        --     control_type = 2,
        --     curr_control_coins = data.gm_control.control_coins,
        -- }
        -- billlog(log_data)

        -- gm_billlog(uid,data, pre_control_coins, add_type, action_type, op_user)
        gm_billlog(uid, data, pre_control_coins, 1, 1)
        check_clear_control_data(uid,data,gm_control)
    end

    --个人控制
    if not gm_control and data.personal_control.control_coins ~= 0 then
        reduce_coins = data.personal_control.control_coins <= coins and data.personal_control.control_coins or coins
        local pre_control_coins = data.personal_control.control_coins
        data.personal_control.control_coins = data.personal_control.control_coins - reduce_coins
        R().exdbsvr(1):send('.gm_coins_mgr','reduce_gm_coins',reduce_coins,{uid=uid,table_type = table_type,gm_control = false}) --减控制库存

        -- local log_data = {
        --     op="update_controldata",
        --     uid = uid,
        --     value = -reduce_coins,
        --     control_type = 1,
        --     curr_control_coins  = data.personal_control.control_coins,
        -- }
        -- billlog(log_data)

        personal_billlog(uid, data, pre_control_coins, nil, 1)

        check_clear_control_data(uid,data,gm_control)
    end
   
    return reduce_coins
end

local function add_curr_control_data(uid,data,coins,table_type,gm_control)
    local add_coins = 0
    if gm_control and data.gm_control.control_coins ~= 0 then
        add_coins = math_abs(data.gm_control.control_coins) <= coins and math_abs(data.gm_control.control_coins) or coins
        local pre_control_coins = data.gm_control.control_coins
        data.gm_control.control_coins = data.gm_control.control_coins + add_coins
        R().exdbsvr(1):send('.gm_coins_mgr','add_gm_coins',add_coins,false,{uid=uid,table_type = table_type,gm_control = true}) --加控制库存

        -- gm_billlog(uid,data, pre_control_coins, add_type, action_type, op_user)
        gm_billlog(uid, data, pre_control_coins, 1, 1)
        check_clear_control_data(uid,data,gm_control)
    end

    if not gm_control and data.personal_control.control_coins ~= 0 then
        add_coins = math_abs(data.personal_control.control_coins) <= coins and math_abs(data.personal_control.control_coins) or coins
        local pre_control_coins = data.personal_control.control_coins
        data.personal_control.control_coins = data.personal_control.control_coins + add_coins
        R().exdbsvr(1):send('.gm_coins_mgr','add_gm_coins',add_coins,false,{uid=uid,table_type = table_type,gm_control = false}) --加控制库存
        

        personal_billlog(uid, data, pre_control_coins, nil, 1)
        check_clear_control_data(uid,data,gm_control)
    end

    return add_coins
end

--更新个控或gm控制值
local function update_player_control_value(uid,data,add_coins,table_type)
    local gm_control = (data.gm_control and data.gm_control.control_coins ~= 0) 
    if gm_control then --有个控优先个控
        --GM控制赢,赢了,减GM控制值
        if data.gm_control.control_coins > 0 and add_coins > 0 then
             return reduce_curr_control_data(uid,data,math_abs(add_coins),table_type,gm_control)
        end
        --GM控制输,真输了,加GM控制值
        if data.gm_control.control_coins < 0 and add_coins < 0 then
            return add_curr_control_data(uid,data,math_abs(add_coins),table_type,gm_control)
        end
    else
        --个人控制赢,赢了,减个人控制值
        if data.personal_control.control_coins > 0 and add_coins > 0 then
           return reduce_curr_control_data(uid,data,math_abs(add_coins),table_type,gm_control)
        end
        --个人控制输,真输了,加个人控制值
        if data.personal_control.control_coins < 0 and add_coins < 0 then
            return add_curr_control_data(uid,data,math_abs(add_coins),table_type,gm_control)
        end
    end

    return 0
end

local function add_player_gm_control(uid,data,info)
    print("___1____add_player_gm_control===========",uid,info)
    if not data.gm_control then
        return false
    end
    print("___2____add_player_gm_control===========", data.gm_control)
    local control_common =  global_configs.personal_control or {}
    local pre_control_coins  = data.gm_control.control_coins
    local pre_personal_control = data.personal_control.control_coins

    clear_personal_control(data) --设置GM控制会清空个人控制

    data.gm_control.control_coins_init = info.control_coins and info.control_coins or data.gm_control.control_coins_init
    data.gm_control.control_coins = info.control_coins and info.control_coins or data.gm_control.control_coins
    data.gm_control.weight = info.control_weight and info.control_weight or data.gm_control.weight
    data.gm_control.win_rate  = info.win_rate and info.win_rate or data.gm_control.win_rate
    data.gm_control.lose_rate = info.lose_rate and info.lose_rate or data.gm_control.lose_rate
    data.gm_control.op_user = info.op_user or 'root'
    if info.is_hundred_game then
        data.gm_control.is_control_hundred_game = info.is_hundred_game
    end 

    -- gm_billlog(uid,data, pre_control_coins, add_type, action_type, op_user)
    gm_billlog(uid, data, pre_control_coins, 0, 0)

    if (info.control_coins or 0) == 0 then
        check_clear_control_data(uid,data,true)
    end

    return {
        uid = uid,
        control_coins  = data.gm_control.control_coins_init,
        curr_control_coins = data.gm_control.control_coins,
        control_weight  = data.gm_control.weight,
        win_rate  = data.gm_control.win_rate,
        lose_rate = data.gm_control.lose_rate,
        pre_control_coins = pre_control_coins,
        is_control_hundred_game = data.gm_control.is_control_hundred_game,
        add_type = 0,
    }
end

local function delete_player_gm_control(uid,data)
    clear_gm_control(data)
end

local function get_player_gm_control(uid,data)
   local ret_data = {
        uid = uid,
        control_coins = data.gm_control.control_coins_init,
        curr_control_coins = data.gm_control.control_coins,
        control_weight = data.gm_control.weight,
        win_rate = data.gm_control.win_rate,
        lose_rate = data.gm_control.lose_rate,
        is_control_hundred_game = data.gm_control.is_control_hundred_game,
    }

    return ret_data
end

local function get_player_personal_control(uid,data)
   local ret_data = {
        uid = uid,
        control_coins = data.personal_control.control_coins,
        weight = data.personal_control.weight,
        win_rate = data.personal_control.win_rate,
        lose_rate = data.personal_control.lose_rate,
    }

    return ret_data
end

local function is_affected(uid,data)
    print("__1__is_affected_______",uid, data.gm_control)
    if data.gm_control and data.gm_control.control_coins ~= 0 then
        if data.gm_control.control_coins > 0 then
            return {control_win = true, control_rate = data.gm_control.win_rate,control_type = 2,control_coins = data.gm_control.control_coins} 
        end
        
        if data.gm_control.control_coins < 0 then
            return {control_win = false, control_rate = data.gm_control.lose_rate,control_type = 2,control_coins = data.gm_control.control_coins}
        end
    end
    print("__2__is_affected_______",uid, data.personal_control)
    if data.personal_control and data.personal_control.control_coins ~= 0 then
        if data.personal_control.control_coins > 0 then
            return {control_win = true, control_rate = data.personal_control.win_rate,control_type = 1,control_coins = data.personal_control.control_coins} 
        end

        if data.personal_control.control_coins < 0 then
            return {control_win = false, control_rate = data.personal_control.lose_rate,control_type = 1,control_coins = data.personal_control.control_coins}
        end
    end

    return false
end

--检测是否添加个控
local function get_online_control(uid,data)
    local control_common =  global_configs.personal_control or {}
    if data.pay_money >= (control_common.xiaoR_level or 1000000) then --大R不加个人控制
        print("___player is daR is not control___",uid)
        return false
    end

    -- if uid == 106041 then 
    --     clear_personal_control(data)
    -- end

    if is_affected(uid,data) then
        print("___player is is in control___",uid)
        return false
    end

    local online_check = control_common.online_check or {}
    local rate = math_random(online_check.rate_min or 0,online_check.rate_max or 0)    
    local not_control_rate = control_common.not_control_rate --不控制区间(百分比)
    local control_win_list = control_common.control_rate_win or {} 
    local control_lose_list = control_common.control_rate_lose or {}

    local exchange_coins = data.exchange_coins
    local pay_money = data.pay_money
    local change_coins = data.coins
    local safe_box = data.safe_box
    local lose_coins = pay_money - change_coins - exchange_coins - safe_box

    --500000 - 200000 - (1050977-1500000)
    print("__1______get_online_control___",uid, lose_coins, pay_money)
    --检查不控制
    local control_value_min =  math_abs(pay_money * (not_control_rate[1]/100))
    local control_value_max =  math_abs(pay_money * (not_control_rate[2]/100))
    if lose_coins >= -control_value_min and lose_coins <= control_value_max then
        print("___player is is not in control range___",uid, lose_coins, -control_value_min, control_value_max)
        return {control_value = 0,win_rate = 0,lose_rate = 0}
    end

    --玩家输钱,控制玩家赢钱
    if lose_coins > 0 then
        local value = math_abs(lose_coins)
        local item = control_win_list[1] or {}
        for k,v in pairs(control_win_list) do
            if value >= (v.lose_min or 0) and value <= (v.lose_max or 0) then
                item = v
                break
            end
        end
        print("__2______get_online_control___",uid, rate, item)
        if math_random(1,100) <= (item.rate or 0) then 
            local trigger_value = rate/100 * value --目标赢金币值
            local control_max = item.max_coins or 0
            trigger_value = (trigger_value >= control_max) and control_max or trigger_value
            print("___player is be controled win___",uid,trigger_value,item.win_rate)
            return {control_value = trigger_value,win_rate = item.win_rate or 0,lose_rate = 0}
        end
    elseif lose_coins < 0 then
        
        --玩家赢钱,控制玩家输钱
        local item = {}
        for _, value in pairs(control_lose_list) do
            if pay_money >= value.min_pay and pay_money < value.max_pay then
                item = value
                break
            end
        end        
        print("__3______get_online_control___",uid, rate, item)
        if math_random(1,100) <= (item.rate or 0) then 
            local trigger_value = rate/100 * lose_coins
            local control_max = item.max_coins or 0
            trigger_value = (trigger_value <= control_max) and control_max or trigger_value
            print("___player is be controled lose___",uid,trigger_value,item.lose_rate)
            return {control_value = -math_abs(trigger_value), win_rate = 0,lose_rate = item.lose_rate or 0,online_lose = true}
        end
    end

    return {control_value = 0,win_rate = 0,lose_rate = 0}
end

--添加个控
local function add_player_personal_control(uid,data,control_data)
    --有GM控制和存在个人控制则不加个人控制值
    if data.gm_control and data.gm_control.control_coins ~= 0 then
        print("add_player_personal_control==111",uid,tostring_r(data.gm_control))
        return
    end

    local control_common =  global_configs.personal_control or {}
    if data.pay_money >= (control_common.xiaoR_level or 1000000) then --大R不加个人控制
        print("add_player_personal_control==222",uid,data.vip_level,(control_common.xiaoR_level or 1000000))
        return
    end

    local pre_control_coins = data.personal_control.control_coins
    if control_data.control_coins then
        data.personal_control.control_coins = data.personal_control.control_coins + control_data.control_coins
        data.personal_control.control_coins_init = control_data.control_coins
    end
    
    if control_data.weight then
        data.personal_control.weight = control_data.weight
    end
    if control_data.win_rate then
        data.personal_control.win_rate = control_data.win_rate
    end
    if control_data.lose_rate then
        data.personal_control.lose_rate = control_data.lose_rate
    end
    data.personal_control.add_type = control_data.add_type

    local pay_money = data.pay_money
    local exchange_coins = data.exchange_coins
    local change_coins = data.coins
    -- local log_data = {
    --    op = "control_data",
    --    uid = uid,
    --    control_type = 1, --1表示个人控，2gm
    --    is_delete = false,
    --    add_type = control_data.add_type, --0gm手动添加 1在线检测
    --    control_coins = control_data.control_coins_init, --控制金额
    --    pre_control_coins = pre_control_coins, --个控变化前
    --    curr_control_coins = data.personal_control.control_coins, --当前个人库存值

    --    curr_coins = data.coins, --玩家当前金额
    --    win_rate  = data.personal_control.win_rate, --赢钱概率
    --    lose_rate = data.personal_control.lose_rate, --输钱概率
    --    shuying = pay_money - exchange_coins - coins, --成功后玩家输赢值
    --    op_user   = 'server',
    --    control_weight  = control_data.weight, --权重
    -- }
    -- billlog(log_data)

    -- gm_billlog(uid,data, pre_control_coins, add_type, action_type, op_user)
    personal_billlog(uid, data, pre_control_coins, control_data.add_type, 0)    
end

---------------------------------------------------------------------------
function CMD.get_base_data(uid) sync_run_by_uid(uid,get_base_data) end
function CMD.get_all_user(uid) sync_run_by_uid(uid,get_all_user) end
function CMD.get_coins(uid) sync_run_by_uid(uid,get_coins) end

function CMD.set_coins(uid,...) sync_run_by_uid(uid,set_coins,...) end
function CMD.add_coins(uid,...) sync_run_by_uid(uid,add_coins,...) end
function CMD.reduce_coins(uid,...) sync_run_by_uid(uid,reduce_coins,...) end
function CMD.reduce_coins_to_empty(uid,...) sync_run_by_uid(uid,reduce_coins_to_empty,...) end
function CMD.can_reduce_coins(uid,...) sync_run_by_uid(uid,can_reduce_coins,...) end
function CMD.caishen_coins(uid,...) sync_run_by_uid(uid,caishen_coins,...) end

function CMD.add_gems(uid,...) sync_run_by_uid(uid,add_gems,...) end
function CMD.reduce_gems(uid,...) sync_run_by_uid(uid,reduce_gems,...) end
function CMD.can_reduce_gems(uid,...) sync_run_by_uid(uid,can_reduce_gems,...) end

function CMD.add_roomcards(uid,...) sync_run_by_uid(uid,add_roomcards,...) end
function CMD.reduce_roomcards(uid,...) sync_run_by_uid(uid,reduce_roomcards,...) end
function CMD.can_reduce_roomcards(uid,...) sync_run_by_uid(uid,can_reduce_roomcards,...) end

function CMD.add_jiabeicards(uid,...) sync_run_by_uid(uid,add_jiabeicards,...) end
function CMD.reduce_jiabeicards(uid,...) sync_run_by_uid(uid,reduce_jiabeicards,...) end
function CMD.can_reduce_jiabeicards(uid,...) sync_run_by_uid(uid,can_reduce_jiabeicards,...) end

function CMD.can_take_compensation(uid,...) sync_run_by_uid(uid,can_take_compensation,...) end
function CMD.take_compensation(uid,...) sync_run_by_uid(uid,take_compensation,...) end

function CMD.can_reduce_item(uid,...) sync_run_by_uid(uid,can_reduce_item,...) end
function CMD.add_item(uid,...) sync_run_by_uid(uid,add_item,...) end
function CMD.reduce_item(uid,...) sync_run_by_uid(uid,reduce_item,...) end

function CMD.pay_one_ticket(uid,...) sync_run_by_uid(uid,pay_one_ticket,...) end

function CMD.buy(uid,...) sync_run_by_uid(uid,buy,...) end

function CMD.pay_lost_coins(uid,...) sync_run_by_uid(uid,pay_lost_coins,...) end
function CMD.give_won_coins(uid,...) sync_run_by_uid(uid,give_won_coins,...) end
function CMD.add_losing_times(uid,...) sync_run_by_uid(uid,add_losing_times,...) end
function CMD.add_wining_times(uid,...) sync_run_by_uid(uid,add_wining_times,...) end
function CMD.add_club_play_times(uid,...) sync_run_by_uid(uid,add_club_play_times,...) end

function CMD.add_item_list(uid,...) sync_run_by_uid(uid,add_item_list,...) end

function CMD.desposit_safe_box(uid,...) sync_run_by_uid(uid,desposit_safe_box,...) end
function CMD.take_out_safe_box(uid,...) sync_run_by_uid(uid,take_out_safe_box,...) end
function CMD.get_safe_box(uid,...) sync_run_by_uid(uid,get_safe_box,...) end

function CMD.add_lose_coins(uid,...) sync_run_by_uid(uid,add_lose_coins,...) end
function CMD.get_lose_coins(uid,...) sync_run_by_uid(uid,get_lose_coins,...) end
function CMD.sub_lose_coins(uid,...) sync_run_by_uid(uid,sub_lose_coins,...) end

function CMD.take_mail_attach(uid,...) sync_run_by_uid(uid,take_mail_attach,...) end
function CMD.reduce_affected_count(uid,...) sync_run_by_uid(uid,reduce_affected_count,...) end
function CMD.set_affected_value(uid,...) sync_run_by_uid(uid,set_affected_value,...) end

-- function CMD.get_curr_control_data(uid,...) sync_run_by_uid(uid,get_curr_control_data,...) end
function CMD.get_charge_count(uid,...) sync_run_by_uid(uid,get_charge_count,...) end

-- function CMD.web_adddata(uid,...) sync_run_by_uid(uid,web_adddata,...) end
-- function CMD.web_updatedata(uid,...) sync_run_by_uid(uid,web_adddata,...) end
-- function CMD.web_switch(uid,...) sync_run_by_uid(uid,web_switch,...) end
-- function CMD.add_control_coins_weight(uid,...) sync_run_by_uid(uid,add_control_coins_weight,...) end
-- function CMD.reduce_control_coins_weight(uid,...) sync_run_by_uid(uid,reduce_control_coins_weight,...) end

--周福利系统
function CMD.add_player_coins_water(uid,...) sync_run_by_uid(uid,add_player_coins_water,...) end
function CMD.get_week_award_info(uid,...) sync_run_by_uid(uid,get_week_award_info,...) end
function CMD.settle_coins_water(uid,...) sync_run_by_uid(uid,settle_coins_water,...) end
function CMD.exchanged_coins(uid,...) sync_run_by_uid(uid,exchanged_coins,...) end
function CMD.get_exchange_record(uid,...) sync_run_by_uid(uid,get_exchange_record,...) end
function CMD.set_week_award_day_count(uid,...) sync_run_by_uid(uid,set_week_award_day_count,...) end
function CMD.set_week_award_can_exchange_award(uid,...) sync_run_by_uid(uid,set_week_award_can_exchange_award,...) end

function CMD.add_play_times(uid,...) sync_run_by_uid(uid,add_play_times,...) end
function CMD.player_cross_day(uid,...) sync_run_by_uid(uid,player_cross_day,...) end
function CMD.player_cross_time(uid,...) sync_run_by_uid(uid,player_cross_time,...) end
function CMD.add_today_win_coins(uid,...) sync_run_by_uid(uid,add_today_win_coins,...) end

function CMD.get_today_data(uid,...) sync_run_by_uid(uid,get_today_data,...) end
function CMD.get_pay_money(uid,...) sync_run_by_uid(uid,get_pay_money,...) end
---fish---
function CMD.sync_winlose(uid,...) sync_run_by_uid(uid,sync_winlose,...) end
function CMD.get_winlose(uid,...) sync_run_by_uid(uid,get_winlose,...) end
function CMD.add_jackpots(uid,...) sync_run_by_uid(uid,add_jackpots,...) end
function CMD.reduce_jackpots(uid,...) sync_run_by_uid(uid,reduce_jackpots,...) end
function CMD.get_jackpots(uid,...) sync_run_by_uid(uid,get_jackpots,...) end
function CMD.set_hitrate(uid,...) sync_run_by_uid(uid,set_hitrate,...) end
function CMD.get_hitrate(uid,...) sync_run_by_uid(uid,get_hitrate,...) end

function CMD.set_person_rate(uid,...) sync_run_by_uid(uid,set_person_rate,...) end
function CMD.get_person_rate(uid,...) sync_run_by_uid(uid,get_person_rate,...) end

function CMD.set_vip_level(uid,...) sync_run_by_uid(uid,set_vip_level,...) end
function CMD.get_vip_level(uid,...) sync_run_by_uid(uid,get_vip_level,...) end

--老虎机-----
function CMD.reduce_free_times(uid,...) sync_run_by_uid(uid,reduce_free_times,...) end
function CMD.add_free_times(uid,...) sync_run_by_uid(uid,add_free_times,...) end

--财神驾到
function CMD.check_caishen_trigger_time(uid,...) sync_run_by_uid(uid,check_caishen_trigger_time,...) end
--个人流水
function CMD.add_person_water(uid,...) sync_run_by_uid(uid,add_person_water,...) end

----大抽奖
function CMD.get_bind_uid(uid,...) sync_run_by_uid(uid,get_bind_uid,...) end
function CMD.set_bind_uid(uid,...) sync_run_by_uid(uid,set_bind_uid,...) end
--玩牌局数
function CMD.add_play_count(uid,...) sync_run_by_uid(uid,add_play_count,...) end

--捕鱼炮台相关
function CMD.set_fish_gun(uid,...) sync_run_by_uid(uid,set_fish_gun,...) end
function CMD.get_fish_gun(uid,...) sync_run_by_uid(uid,get_fish_gun,...) end

--首冲活动
function CMD.check_player_first_charge(uid,...) sync_run_by_uid(uid,check_player_first_charge,...) end
function CMD.update_first_charge_status(uid,...) sync_run_by_uid(uid,update_first_charge_status,...) end

function CMD.add_player_fee_coins(uid,...) sync_run_by_uid(uid,add_player_fee_coins,...) end

--获取俱乐部id
function CMD.get_club_id(uid,...) sync_run_by_uid(uid,get_club_id,...) end
function CMD.set_club_id(uid,...) sync_run_by_uid(uid,set_club_id,...) end
function CMD.get_clubid_and_viplevel(uid,...) sync_run_by_uid(uid,get_clubid_and_viplevel,...) end

function CMD.set_award_free_count(uid,...) sync_run_by_uid(uid,set_award_free_count,...) end
-- function CMD.get_player_control_rate(uid,...) sync_run_by_uid(uid,get_player_control_rate,...) end

--校验兑换提现
function CMD.check_exchange(uid,...) sync_run_by_uid(uid,check_exchange,...) end
function CMD.get_exchange_need_water(uid,...) sync_run_by_uid(uid,get_exchange_need_water,...) end
function CMD.reduce_exchange_need_water(uid,...) sync_run_by_uid(uid,reduce_exchange_need_water,...) end
function CMD.add_exchange_need_water(uid,...) sync_run_by_uid(uid,add_exchange_need_water,...) end


--红包记录
function CMD.add_fhb_record(uid,...) sync_run_by_uid(uid,add_fhb_record,...) end
function CMD.get_fhb_record(uid,...) sync_run_by_uid(uid,get_fhb_record,...) end
function CMD.add_qhb_record(uid,...) sync_run_by_uid(uid,add_qhb_record,...) end
function CMD.get_qhb_record(uid,...) sync_run_by_uid(uid,get_qhb_record,...) end

--福利中心
function CMD.get_welfare_info(uid,...) sync_run_by_uid(uid,get_welfare_info,...) end
--测试接口修改跨天检测时间
function CMD.reset_time(uid,...) sync_run_by_uid(uid,reset_time,...) end
--兑换成功
function CMD.exchange_success(uid,...) sync_run_by_uid(uid,exchange_success,...) end

--每日首充
function CMD.update_day_charge_status(uid,...) sync_run_by_uid(uid,update_day_charge_status,...) end

--增加累计赢金
function CMD.add_total_coins(uid,...) sync_run_by_uid(uid,add_total_coins,...) end

--增加累计投注
function CMD.add_total_lose_coins(uid,...) sync_run_by_uid(uid,add_total_lose_coins,...) end

--今日输赢金
function CMD.add_win_lose_coins(uid,...) sync_run_by_uid(uid,add_win_lose_coins,...) end


function CMD.update_player_control_value(uid,...) sync_run_by_uid(uid,update_player_control_value,...) end
function CMD.add_player_gm_control(uid,...) sync_run_by_uid(uid,add_player_gm_control,...) end
function CMD.delete_player_gm_control(uid,...) sync_run_by_uid(uid,delete_player_gm_control,...) end
function CMD.get_player_gm_control(uid,...) sync_run_by_uid(uid,get_player_gm_control,...) end
function CMD.get_player_personal_control(uid,...) sync_run_by_uid(uid,get_player_personal_control,...) end
function CMD.get_online_control(uid,...) sync_run_by_uid(uid,get_online_control,...) end
function CMD.is_affected(uid,...) sync_run_by_uid(uid,is_affected,...) end
function CMD.delete_personal_control(uid,...) sync_run_by_uid(uid,delete_personal_control,...) end
function CMD.add_curr_control_data(uid,...) sync_run_by_uid(uid,add_curr_control_data,...) end
function CMD.reduce_curr_control_data(uid,...) sync_run_by_uid(uid,reduce_curr_control_data,...) end
function CMD.add_player_personal_control(uid,...) sync_run_by_uid(uid,add_player_personal_control,...) end
---------------------------------------------------------------------------

function dispatch_cmd(session,source,action,...)
    CMD[action](...)
end


function start()
    skynet.start(function()
        skynet.dispatch("lua",function(session,addr,action,...)
            dbglog('============got params ...... ',action,...)
            -- CMD[action](...)
            dispatch_cmd(session,addr,action,...)
        end)
        global_configs = setmetatable({},{
            __index = function(t,k) 
                return sharedata.query(k)
            end
        })
    end)
end

_START(function()
    print('now this service is starting')
    init()
    start()
end)
